package com.jxm.reflection;

import org.junit.Test;

import java.lang.reflect.*;

/**
 * @Author: jxm
 * @Description:
 * @Date: 2024-1-4 11:38
 * @Version: 1.0
 */
public class ReflectionTest {

    /**
     * 通过反射获取Person类的基本信息
     * @throws Exception
     */
    @Test
    public void test1() throws Exception{
        Class<?> zz = Class.forName("com.jxm.reflection.Person");
        System.out.println(zz.getName());
        String simpleName = zz.getSimpleName();
        System.out.println("以下是 "+simpleName+"类的基本信息-----------");
        //获取Person类所在的包
        Package aPackage = zz.getPackage();
        System.out.println("所在的包："+aPackage);
        Class<?> superclass = zz.getSuperclass();
        System.out.println(simpleName+" 类的超类是： "+superclass.getName());
        Class<?>[] interfaces = zz.getInterfaces();
        System.out.print(simpleName+" 类所实现的接口： ");
        for (Class c:interfaces) {
            System.out.println("\t" + c.getName());
        }
        //每个修饰符对应一个int常量，返回的修饰符信息将类所拥有的修饰符以”或“运算组合
        //通过与Modifier类中的常量进行”与“运算即可判断该类型是否拥有某个修饰符
        int modifier = zz.getModifiers();
        if((modifier & Modifier.PUBLIC) == Modifier.PUBLIC){
            System.out.println("访问修饰符是：public");
        }else{
            System.out.println("访问修饰符是：default(package)");
        }
        if((modifier & Modifier.FINAL) == Modifier.FINAL){
            System.out.println("这个类是：final的");
        }
        if((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT){
            System.out.println("这个类是抽象类");
        }
        if((modifier & Modifier.INTERFACE) == Modifier.INTERFACE){
            System.out.println("这是一个接口");
        }
    }

    /**
     * 通过反射获取Person类声明的构造方法信息
     */
    @Test
    public void test2() throws Exception{
        Class<Person> zz = Person.class;
        Constructor<?>[] constructors = zz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            String name = constructor.getName();
//            System.out.println("构造方法名称："+name);
            Parameter[] parameters = constructor.getParameters();
            for (Parameter parameter : parameters) {
                System.out.print(parameter+"\t");
            }
            System.out.println();
            Class<?>[] params = constructor.getParameterTypes();
            if (params.length == 0){
                System.out.println("该构造方法没有参数");
            }else{
                System.out.print("该构造方法的参数列表为:[");
                for(int i=0;i<params.length;i++){
                    if(i!=0)
                        System.out.print(",");
                    System.out.print(params[i].getName());
                }
                System.out.println("]");
            }
            System.out.println("-------------------------------");
        }

        //获取指定构造防范
        Constructor<Person> declaredConstructor = zz.getDeclaredConstructor(String.class);
        declaredConstructor.setAccessible(true);
        Person person = declaredConstructor.newInstance("zhangsn");
        System.out.println(person.getName());
        System.out.println("====================");
        Constructor<Person> declaredConstructor1 = zz.getDeclaredConstructor();
        Person person1 = declaredConstructor1.newInstance();
        System.out.println(person1.getName());
    }

    /**
     * 通过反射获取Person类中的所有属性
     *  常用方法：
     * Field.getType()：返回这个变量的类型
     * Field.getGenericType()：如果当前属性有签名属性类型就返回，否则就返回 Field.getType()
     * isEnumConstant() ： 判断这个属性是否是枚举类
     *
     * getName() ： 获取属性的名字
     * get(Object obj) 返回指定对象obj上此 Field 表示的字段的值
     * set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
     * @throws Exception
     */
    @Test
    public void test3() throws Exception{
        Person person = new Person();
        Class<? extends Person> zz = person.getClass();
        //获取公共所有属性
        Field[] fields = zz.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("------------------------");
        //获取指定公共属性
        Field height = zz.getField("message");
        System.out.println(height.getName());

        System.out.println("------------------------");
        //获取所有属性
        Field[] declaredFields = zz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            System.out.println(declaredField.getName());
            System.out.println("\t"+declaredField.get(person)+"\n");
        }

        System.out.println("------------------------");
        //获取指定任何属性
        Field declaredField = zz.getDeclaredField("address");
        System.out.println(declaredField.getName());
        declaredField.set(person,"贵阳市观山湖区");
        System.out.println(declaredField.get(person));
        System.out.println("------------------------");
        Field declaredField2 = zz.getDeclaredField("age");
        System.out.println(declaredField2.getInt(person));


    }

    /**
     *  通过反射获取Person类中的所有方法
     */
    @Test
    public void test4() throws Exception{
        Person person = new Person();
        Class<? extends Person> zz = person.getClass();
        Method[] declaredMethods = zz.getDeclaredMethods();
        for (Method method : declaredMethods) {
//            System.out.println("方法名: "+method.getName());
//            System.out.println("返回值类型:"+method.getReturnType().getName() + "\n");

            //获取方法的参数列表
            Class[] params=method.getParameterTypes();
            if(params.length==0){
                System.out.println("该方法没有参数");
            }else{
                System.out.print("该方法的参数列表为:[");
                for (int i=0;i<params.length;i++){
                    if(i!=0){
                        System.out.println(",");
                    }
                    System.out.print(params[i].getName());
                }
                System.out.println("]");
            }

            System.out.print("访问修饰符:");
            int modifier=method.getModifiers();
            //判断该方法的访问修饰符
            if((modifier & Modifier.PUBLIC)==Modifier.PUBLIC){
                System.out.println("public");
            }else if((modifier & Modifier.PROTECTED)==Modifier.PROTECTED){
                System.out.println("protected");
            }else if((modifier & Modifier.PRIVATE)==Modifier.PRIVATE){
                System.out.println("private");
            }else {
                System.out.println("default(package)");
            }
            //判断该方法是否有static修饰符
            if((modifier&Modifier.STATIC)==Modifier.STATIC)
                System.out.println("这是一个静态方法");
            //判断该方法是否有final修饰符
            if((modifier&Modifier.FINAL)==Modifier.FINAL)
                System.out.println("这是一个final方法");
            //判断该方法是否有ABSTRACT修饰符
            if((modifier&Modifier.ABSTRACT)==Modifier.ABSTRACT)
                System.out.println("这是一个抽象方法");
            //判断该方法是否有synchronized修饰符
            if((modifier&Modifier.SYNCHRONIZED)==Modifier.SYNCHRONIZED)
                System.out.println("这是一个同步方法");

            //获取方法所属的类或接口的class实例
            Class declaringClass=method.getDeclaringClass();
            System.out.println("方法声明在:"+declaringClass.getName()+"中");

            //获取方法抛出的异常处理，即throws子句中声明的异常
            Class[] exceptions=method.getExceptionTypes();
            if(exceptions.length>0){
                System.out.print("该方法抛出的异常有:[");
                for(int i=0;i<exceptions.length;i++){
                    if(i!=0)
                        System.out.print(",");
                    System.out.print(exceptions[i].getName());
                }
                System.out.println("]");
            }
            System.out.println("--------------------------------");
        }

        System.out.println("=======================================");
        //获取指定方法
        Method setName = zz.getDeclaredMethod("setName", String.class);
        System.out.println(setName.getName());
    }


    /**
     * 通过反射对Person类构造方法进行调用与赋值
     */
    @Test
    public void test5() throws Exception{
        Class<?> clz = Class.forName("com.jxm.reflection.Person");
        //获取Person的无参构造:public Person（）
        Constructor c1=null;
        c1= clz.getDeclaredConstructor();
        //Person的无参构造为public,这里可以直接访问
        Object obj = c1.newInstance();
        System.out.println(obj);

        Constructor c2=null;
        //获取Person的单参构造 private Person(String)
        c2= clz.getDeclaredConstructor(String.class);
        //Person的单参构造为private,这里已超出其他访问范围，不能直接访问
        //通过setAccessable方法，设定为可以访问
        c2.setAccessible(true);
        obj=c2.newInstance("New Person");
        System.out.println(obj);

        //获取Person的三参构造:protected Person(String,String,String)
        Constructor c3=clz.getDeclaredConstructor(String.class,String.class,String.class);
        //Person的三参构造为protected,这里已超出其访问范围，不能直接访问
        //通过setAccessable方法，设定为可以访问
        c3.setAccessible(true);
        obj=c3.newInstance("张三","长沙","你好！");
        System.out.println(obj);
    }

    /**
     * 通过反射对Person属性进行赋值与取值
     */
    @Test
    public void test6() throws Exception{
        //通过反射加载一个Person实例
        Class<Person> clz = Person.class;
        Person person = clz.newInstance();

        //获取private String name属性
        Field name=clz.getDeclaredField("name");
        //name属性为private,这里已超出其访问范围，不能直接访问
        //通过setAccessable方法，设定为可以访问
        name.setAccessible(true);
        //先取值看一下
        System.out.println("赋值前的name:"+name.get(person));
        //为name赋值
        name.set(person,"张三");
        //展示赋值效果
        System.out.println("赋值后的name:"+name.get(person));
    }
}
